/***************************************************************************
 * This program is free software; you can redistribute it and/or           *
 * modify it under the terms of the GNU General Public License             *
 * as published by the Free Software Foundation; either version 2          *
 * of the License, or (at your option) any later version.                  *
 *                                                                         *
 * This program is distributed in the hope that it will be useful,         *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
 * GNU General Public License for more details.                            *
 *                                                                         *
 * You should have received a copy of the GNU General Public License       *
 * along with this program; if not, write to the Free Software Foundation, *
 * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.         *
 *                                                                         *
 *   Copyright (C) 2007,2008 by Ivan Vucica                                *
 *   ivucica@gmail.com                                                     *
 ***************************************************************************/

#include <iostream>

#include <readline/readline.h>
#include <readline/history.h>

#include <stdarg.h>
#include <fstream>

#include "logocontext.h"
#include "logointerpreter.h"
#include "primlib.h"
LogoContext globalcontext;

void onlogo_printf (const char* txt, ...) {
	va_list vl;
	va_start(vl, txt);
	static char tx[10000];
	vsnprintf(tx, 10000, txt, vl);
	std::cout << tx;
	va_end(vl);
}


int main(int argc, char** argv)
{


	std::cout << "ONLogo v1.0" << std::endl << " (c) 2007 OBJECT Networks" << std::endl;


	globalcontext.RegisterProcedure(std::string("PRINT"), prm_print , 1);
	globalcontext.RegisterProcedure(std::string("PR"), prm_print , 1);
	globalcontext.RegisterProcedure(std::string("POTS"), prm_pots , 0);
	globalcontext.RegisterProcedure(std::string("__VARIABLES"), prm___variables , 0);
	globalcontext.RegisterProcedure(std::string("MAKE"), prm_make, 2);
	globalcontext.RegisterProcedure(std::string("FORWARD"), prm_forward, 1);
	globalcontext.RegisterProcedure(std::string("FD"), prm_forward, 1);
	globalcontext.RegisterProcedure(std::string("RIGHT"), prm_right, 1);
	globalcontext.RegisterProcedure(std::string("RT"), prm_right, 1);
	globalcontext.RegisterProcedure(std::string("BACK"), prm_back, 1);
	globalcontext.RegisterProcedure(std::string("BK"), prm_back, 1);
	globalcontext.RegisterProcedure(std::string("LEFT"), prm_left, 1);
	globalcontext.RegisterProcedure(std::string("LT"), prm_left, 1);
	globalcontext.RegisterProcedure(std::string("SHOWTURTLE"), prm_showturtle, 0);
	globalcontext.RegisterProcedure(std::string("ST"), prm_showturtle, 0);
	globalcontext.RegisterProcedure(std::string("HIDETURTLE"), prm_hideturtle, 0);
	globalcontext.RegisterProcedure(std::string("HT"), prm_hideturtle, 0);
	globalcontext.RegisterProcedure(std::string("SETPC"), prm_setpc, 1);
	///////////////// procedures below need documentation ///////////////////
	globalcontext.RegisterProcedure(std::string("PENDOWN"), prm_pendown, 0);
	globalcontext.RegisterProcedure(std::string("PD"), prm_pendown, 0);
	globalcontext.RegisterProcedure(std::string("PENUP"), prm_penup, 0);
	globalcontext.RegisterProcedure(std::string("PU"), prm_penup, 0);
	globalcontext.RegisterProcedure(std::string("CLEARSCREEN"), prm_clearscreen, 0);
	globalcontext.RegisterProcedure(std::string("CS"), prm_clearscreen, 0);
	globalcontext.RegisterProcedure(std::string("REPEAT"), prm_repeat, 2);
	globalcontext.RegisterProcedure(std::string("FOR"), prm_for, 4);
	globalcontext.RegisterProcedure(std::string("IF"), prm_if, 2);
	globalcontext.RegisterProcedure(std::string("IFELSE"), prm_if, 3);
	globalcontext.RegisterProcedure(std::string("AND"), prm_and, 2);
	globalcontext.RegisterProcedure(std::string("FIRST"), prm_first, 1);
	globalcontext.RegisterProcedure(std::string("BYE"), prm_bye, 0);


	{
		LogoInterpreter li("CLEARSCREEN");
		try {
			li.Execute(globalcontext);
		} catch (std::string s ) {
			std::cout << "Clearing screen failed: " << std::endl << " ==> " << s << std::endl;
		}
	}



	{
		std::fstream startupfile("startup.lgo");
		if (startupfile.is_open()) {
			std::string stext, startup;
			while (getline(startupfile, stext))
				startup = startup + stext + "\n";
			startupfile.close();
			std::cout << startup << std::endl;
			LogoInterpreter li(startup);
			try {
				Token a = li.Execute(globalcontext);
			} catch (std::string s ) {
				std::cout << "Running startup logo file failed." << std::endl << " ==> " << s << std::endl;
			}


		}

	}

	std::string collection;
	bool collectionmode;
	for (;;) {


		char * command;
		if (!collectionmode) {

			command = readline("? ");
			LogoInterpreter li(command);
			if (li.GetFirstToken().type != Token::TT_TO) {
				try {
					Token ret = li.Execute(globalcontext);
					if (ret.type != Token::TT_UNDEFINED) {
						LogoContext lc;
						throw std::string("You don't say what to do with ") + ret.Describe() + " (" + ret.Evaluate(globalcontext, lc).Describe() + ")";
					}
				} catch (std::string s) {
					std::cout << "Error: " << s << std::endl;
				}
			} else {
				collection = std::string(command) + "\n";
				collectionmode = true;
			}

		} else {
			command = readline("> ");
			collection += std::string(command) + "\n";
			if (std::string(command) == "END") {
				LogoInterpreter li(collection);
				li.Execute(globalcontext);

				collectionmode = false;
			}
		}
		add_history(command);
		free(command);

	}
	return 0;
}

